﻿namespace LogManager.Gui.ViewModels
{
    using LogManager.Core.Infrastructure.Logging;
    using LogManager.Core.Models;
    using LogManager.Gui.Helpers;
    using LogManager.Gui.UI.Representations;
    using LogManager.Gui.Views;
    using LogManager.Utils.Unity;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Waf.Applications;
    using System.Waf.Applications.Services;
    using System.Windows;
    using System.Windows.Input;
    using LogManager.Core.Factories;
    using LogManager.Gui.Factories;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class MainViewModel : ViewModelBase<IMainView>, IMainViewModel
    {
        public const string XSD_PATH = "Config/schema.xsd";
        public const string DEFAULT_CONFIG_PATH = "Config/configuration.xml";

        IConfiguration IMainViewModel.Configuration
        {
            get { return this.Configuration; }
        }

        private Configuration _configuration;
        public virtual Configuration Configuration
        {
            get
            {
                return _configuration;
            }
            protected set
            {
                _configuration = value;

                if (_configuration != null)
                {
                    this.WarehousesVm = _configuration.Warehouses.GetSyncWrapper(m => this._viewModelFactory.CreateWarehouseViewModel(m));
                    this.SettingsViewModel = this._viewModelFactory.CreateSettingsViewModel(_configuration.Settings);
                    this.CheckLocationsViewModel = this._viewModelFactory.CreateCheckLocationsViewModel(_configuration);
                    this.ExecuteArchivingViewModel = this._viewModelFactory.CreateExecuteArchivingViewModel(_configuration);
                    this._configuration.Changed += Configuration_Changed;
                }
            }
        }

        public virtual bool ArePendingChanges { get; protected set; }
        public virtual ReadOnlyObservableCollection<IWarehouseViewModel> WarehousesVm { get; protected set; }
        public virtual ISettingsViewModel SettingsViewModel { get; protected set; }
        public virtual ICheckLocationsViewModel CheckLocationsViewModel { get; protected set; }
        public virtual IExecuteArchivingViewModel ExecuteArchivingViewModel { get; protected set; }
        public virtual string CurrentConfigurationPath { get; protected set; }
        public virtual ObservableCollection<LogItem> Logs { get; protected set; }

        [DependsUpon("Configuration")]
        public virtual bool IsValidState
        {
            get
            {
                return this.Configuration != null;
            }
        }

        [DependsUpon("ArePendingChanges")]
        [DependsUpon("FileTitle")]
        public string Title
        {
            get
            {
                var changes = this.ArePendingChanges ? "*" : string.Empty;
                var prefix = changes + FileTitle;
                return prefix + " - " + ApplicationInfo.ProductName;
            }
        }

        [DependsUpon("Configuration")]
        [DependsUpon("CurrentConfigurationPath")]
        public string FileTitle
        {
            get
            {
                if (Configuration == null)
                    return "Aucun";

                if (string.IsNullOrEmpty(CurrentConfigurationPath))
                    return "Nouvelle configuration";

                return CurrentConfigurationPath;
            }
        }

        public readonly IFileDialogService _fileDialogService;
        public readonly IMessageService _messageService;
        public readonly IViewModelFactory _viewModelFactory;
        public readonly IXmlElementFactory _xmlElementFactory;

        public MainViewModel(IMainView view, IFileDialogService fileDialogService, IMessageService MessageService, IViewModelFactory viewModelFactory, IXmlElementFactory xmlElementFactory)
            : base(view)
        {
            this._messageService = MessageService;
            this._fileDialogService = fileDialogService;
            this._viewModelFactory = viewModelFactory;
            this._xmlElementFactory = xmlElementFactory;

            this.Logs = new ObservableCollection<LogItem>();
            Log.Logger.LogAdded += LogService_LogAdded;
        }

        private void LogService_LogAdded(LogResult log)
        {
            this.Logs.Insert(0, new LogItem(log));
        }

        private void Configuration_Changed(object sender, object e)
        {
            this.ArePendingChanges = true;
        }

        public void OpenDefault()
        {
            this.OpenFile(DEFAULT_CONFIG_PATH);
        }

        public void CreateNewFile()
        {
            Clear();
            this.Configuration = this._xmlElementFactory.CreateNewConfiguration();
            this.ArePendingChanges = true;
        }

        public void OpenFile(string filePath)
        {
            Clear();

            this.Configuration = this._xmlElementFactory.CreateConfiguration(filePath, XSD_PATH);
            this.CurrentConfigurationPath = filePath;

            Log.Logger.AddSuccess("Fichier chargé", filePath);
        }

        public void SaveFile(string filePath)
        {
            if (this.Configuration == null)
                return;

            this.Configuration.Save(filePath);
            this.CurrentConfigurationPath = filePath;
            this.ArePendingChanges = false;
            Log.Logger.AddSuccess("Fichier enregistré", filePath);
        }

        #region Commands

        public ICommand CreateNewFileCommand { get { return new DelegateCommand(OnCreateNewFile); } }
        private void OnCreateNewFile()
        {
            if (!AskSavingPendingChanges())
                return;

            CreateNewFile();
        }

        public ICommand OpenFileCommand { get { return new DelegateCommand(OnOpenFile); } }
        private void OnOpenFile()
        {
            if (!AskSavingPendingChanges())
                return;

            var result = this._fileDialogService.ShowOpenFileDialog(new FileType("Fichier de configuration", ".xml"));

            if (result.IsValid)
            {
                this.OpenFile(result.FileName);
            }
        }

        public ICommand SaveFileCommand { get { return new DelegateCommand(OnSaveFile, () => this.IsValidState); } }
        private void OnSaveFile()
        {
            if (!string.IsNullOrEmpty(this.CurrentConfigurationPath))
            {
                this.SaveFile(this.CurrentConfigurationPath);
            }
            else
            {
                OnSaveFileAs();
            }
        }

        public ICommand SaveFileAsCommand { get { return new DelegateCommand(OnSaveFileAs, () => this.IsValidState); } }
        private void OnSaveFileAs()
        {
            var result = this._fileDialogService.ShowSaveFileDialog(new FileType("Fichier de configuration", ".xml"));

            if (result.IsValid)
            {
                this.SaveFile(result.FileName);
            }
        }

        public ICommand AddWarehouseCommand { get { return new DelegateCommand(OnAddWarehouse, () => this.IsValidState); } }
        private void OnAddWarehouse()
        {
            var newWarehouse = this.Configuration.AddNewWarehouse();
            this.View.ExpandAndSelectItem(newWarehouse);
            Log.Logger.AddInfo("Entrepôt créé", newWarehouse.Name);
        }

        #endregion

        public void OnWindowClosing(CancelEventArgs e)
        {
            e.Cancel = !AskSavingPendingChanges();
        }

        private void Clear()
        {
            if (Configuration != null)
                this.Configuration.Warehouses.Clear();

            this.CurrentConfigurationPath = string.Empty;
            this.Configuration = null;
            this.ArePendingChanges = false;
        }

        private bool AskSavingPendingChanges()
        {
            if (this.ArePendingChanges)
            {
                var result = this._messageService.ShowQuestion(string.Format("Voulez-vous enregistrer les modifications de \n{0} ? ", this.FileTitle));

                if (result.HasValue)
                {
                    if (result.Value)
                    {
                        this.OnSaveFile();
                    }
                }
                else
                {
                    return false;
                }
            }

            return true;
        }
    }
}
